﻿/*************************************************************************
 *  Copyright (C), 2017-2018, YangTao tech. Co., Ltd.
 *  FileName: SocketClient.cs
 *  Author: YangTao   Version: 1.0   Date: 11/28/2016
 *  Email:YangTao_Unity3D@163.com
 *  Version Description:
 *    
 *  File Description:
 *    
 *  Class List:
 *    <ID>           <name>             <description>
 *     1.         SocketClient             
 *  Function List:
 *    <ID>           <name>             <description>
 *     1.
 *  History:
 *    <ID>    <author>      <time>      <version>      <description>
 *     1.     YangTao     11/28/2016       1.0        Build this file.
 *************************************************************************/
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Collections.Generic;


public class SocketClient
{
    /// <summary>客户端SOCKET</summary> 
    Socket m_clientSocket;
    /// <summary>存放消息数据</summary>
    byte[] m_msgBuffer;
    /// <summary>等待连接线程</summary>
    Thread m_waitConnectThread;
    /// <summary>接收消息线程</summary>
    Thread m_recMsgThread;
    /// <summary>处理消息线程</summary>
    Thread m_analyseThd;
    /// <summary>心跳包线程</summary>
    Thread m_heartbeatThd;
    /// <summary>客户端是否开启服务</summary>
    bool m_isClientStart;
    /// <summary>是否接受消息</summary>
    bool m_isReceiveMsg;
    /// <summary>是否处理消息</summary> 
    bool m_isAnalyseMsg;
    /// <summary>是否为心跳包</summary> 
    public bool m_isHeartBeat;
    /// <summary>消息队列</summary> 
    List<string> m_msgList;//消息队列
    /// <summary>消息管理</summary> 
    MsgManage m_msgManage;
    /// <summary>命令消息管理</summary> 
    OrderMsgManage m_orderMsgManage;
    /// <summary>连接是否成功</summary> 
    public Void_Delegate IsConnectCallback;
    /// <summary>收到消息：来自哪里 内容</summary> 
    public Void_StringStringDelegate ReceiveMsgCallback;
    /// <summary>客户端自身IP</summary>    
    public string m_clientIP;
    /// <summary>服务端IP</summary>    
    public string m_serverIP;
    /// <summary>获得的消息头</summary>
    HeadSign m_head;
    /// <summary>获得的命令消息头</summary>
    OrderHeadSign m_orderHead;
    /// <summary>获得的IPList</summary>
    List<string> m_ipList;
    /// <summary>获得的消息（去掉标识）</summary>
    string m_content;
    /// <summary>获得的命令IPList</summary>
    List<string> m_orderIPList;

    public Void_ListStringDelegate AddClientCallback;
    public Void_ListStringDelegate DeletClientCallback;

    /// <summary>初始化</summary>    
    public void Init()
    {
        m_clientSocket = null;
        m_msgBuffer = new byte[2048];
        m_waitConnectThread = null;
        m_recMsgThread = null;
        m_analyseThd = null;
        m_heartbeatThd = null;
        m_isClientStart = false;
        m_isReceiveMsg = false;
        m_isAnalyseMsg = false;
        m_isHeartBeat = true;
        m_msgList = new List<string>();
        m_msgManage = new MsgManage();
        m_orderMsgManage = new OrderMsgManage();
        m_ipList = new List<string>();
        m_orderIPList = new List<string>();
        m_content = "";
        m_clientIP = "";
        m_serverIP = "";
    }

    /// <summary>是否连接</summary>
    public bool InitNetwork()
    {
        if (m_isClientStart)
            return false;

        m_isClientStart = true;
        if (m_clientSocket == null)
            m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        if (m_analyseThd == null)
            m_analyseThd = new Thread(AnalyseMsg);

        if (m_heartbeatThd == null)
            m_heartbeatThd = new Thread(Heartbeat);
        m_isAnalyseMsg = true;
        m_analyseThd.Start();
        m_heartbeatThd.Start();

        if (m_waitConnectThread == null)
            m_waitConnectThread = new Thread(new ThreadStart(WaitConnect));
        m_waitConnectThread.Start();

        return true;
    }

    /// <summary>等待连接</summary>
    void WaitConnect()
    {
        IPAddress ipAddress = IPAddress.Parse(m_serverIP);
        IPEndPoint ipep = new IPEndPoint(ipAddress, 8888);
        m_clientSocket.Connect(ipep);
        m_clientIP = m_clientSocket.LocalEndPoint.ToString();
        IsConnectCallback();

        m_isReceiveMsg = true;
        m_recMsgThread = new Thread(new ThreadStart(ReceMsg));
        m_recMsgThread.Start();
    }

    /// <summary>接收消息</summary>
    void ReceMsg()
    {
        while (m_isReceiveMsg)
        {
            int len = m_clientSocket.Receive(m_msgBuffer);
            string msg = Encoding.UTF8.GetString(m_msgBuffer, 0, len);
            m_msgList.Add(msg);
        }
    }

    /// <summary>解析消息</summary>
    void AnalyseMsg()
    {
        while (m_isAnalyseMsg)
        {
            Thread.Sleep(100);
            if (m_msgList.Count > 0)
            {
                if (m_msgManage.AnalysisMsg(m_msgList[0]))//解析消息
                {
                    m_head = m_msgManage.GetHeadSign();
                    m_ipList = m_msgManage.GetIPPortList();
                    m_content = m_msgManage.GetContent();

                    DealWithMsgCondition();
                }
                else if (m_orderMsgManage.AnalysisMsg(m_msgList[0]))//解析命令
                {
                    m_orderHead = m_orderMsgManage.GetOrderHeadSign();
                    m_orderIPList = m_orderMsgManage.GetIPPortList();

                    DealWithOrderMsgCondition();
                }

                m_msgList.RemoveAt(0);
            }
        }
    }

    void DealWithMsgCondition()
    {
        if (m_head == HeadSign.STOC)
        {
            if (ReceiveMsgCallback != null)
                ReceiveMsgCallback(m_ipList[0], m_content);
            m_isHeartBeat = true;
        }
        else if (m_head == HeadSign.HEARTBEAT)
        {
            m_isHeartBeat = true;
        }
    }

    void DealWithOrderMsgCondition()
    {
        if (m_orderHead == OrderHeadSign.ADDCLIENT)
        {
            AddClientCallback(m_orderIPList);
        }
        else if (m_orderHead == OrderHeadSign.DELETCLIENT)
        {
            DeletClientCallback(m_orderIPList);
        }
    }

    /// <summary>发送消息给服务器</summary>
    public void SendContent(string content)
    {
        List<string> list = new List<string>();
        list.Add(m_clientIP);
        string str = m_msgManage.GetMsg(HeadSign.TOSERVER, content, list);
        m_clientSocket.Send(Encoding.UTF8.GetBytes(str));
    }

    /// <summary>
    /// 发送消息给链表中客户端
    /// </summary>
    /// <param name="ipPortList">要发送到的客户端IP，不用包含发送方</param>
    /// <param name="content">消息</param>
    public void SendContent(List<string> ipPortList, string content)
    {
        List<string> list = new List<string>();
        list.Add(m_clientIP);
        PreDefScrp.ListAddTo<string>(ipPortList, ref list);
        string str = m_msgManage.GetMsg(HeadSign.TOCLIENT, content, list);
        m_clientSocket.Send(Encoding.UTF8.GetBytes(str));
    }

    /// <summary>发送删除客户端命令给服务器</summary>
    public void SendDeletOrder()
    {
        List<string> clientList = new List<string>();
        clientList.Add(m_clientIP);
        string str = m_orderMsgManage.GetMsg(OrderHeadSign.DELETCLIENT, clientList);
        if (m_clientSocket != null)
            m_clientSocket.Send(Encoding.UTF8.GetBytes(str));
    }

    void Heartbeat()
    {
        while (m_isAnalyseMsg)
        {
            Thread.Sleep(3000);
            try
            {
                List<string> list = new List<string>();
                list.Add(m_clientIP);
                string content = "";
                string str = m_msgManage.GetMsg(HeadSign.HEARTBEAT, content, list);
                m_clientSocket.Send(Encoding.UTF8.GetBytes(str));
            }
            catch
            {
                m_isHeartBeat = false;
            }
        }
    }

    /// <summary>关闭Socket及线程</summary>
    public void CloseNetwork()
    {
        m_isReceiveMsg = false;
        m_isAnalyseMsg = false;

        if (m_clientSocket != null)
            m_clientSocket.Close();

        if (m_waitConnectThread != null)
            m_waitConnectThread.Abort();

        if (m_recMsgThread != null)
            m_recMsgThread.Abort();

        if (m_analyseThd != null)
            m_analyseThd.Abort();

        if (m_heartbeatThd != null)
            m_heartbeatThd.Abort();
    }
}
